﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Diagnostics
Imports System.Globalization
Imports System.Workflow.Runtime

Namespace System.Workflow.ComponentModel
    Public NotInheritable Class ActivityExecutionContextManager
        ' Methods
        Friend Sub New(ByVal ownerContext As ActivityExecutionContext)
            Me.ownerContext = ownerContext
            Dim list As IList([Of] Activity) = DirectCast(Me.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty), IList([Of] Activity))
            If (Not list Is Nothing) Then
                Dim activity As Activity
                For Each activity In list
                    Me.executionContexts.Add(New ActivityExecutionContext(activity))
                Next
            End If
        End Sub

        Public Sub CompleteExecutionContext(ByVal childContext As ActivityExecutionContext)
            If (Me.ownerContext Is Nothing) Then
                Throw New ObjectDisposedException("ActivityExecutionContextManager")
            End If
            Me.CompleteExecutionContext(childContext, False)
        End Sub

        Public Sub CompleteExecutionContext(ByVal childContext As ActivityExecutionContext, ByVal forcePersist As Boolean)
            If (Me.ownerContext Is Nothing) Then
                Throw New ObjectDisposedException("ActivityExecutionContextManager")
            End If
            If (childContext Is Nothing) Then
                Throw New ArgumentNullException("childContext")
            End If
            If (childContext.Activity Is Nothing) Then
                Throw New ArgumentException("childContext", SR.GetString("Error_MissingActivityProperty"))
            End If
            If (childContext.Activity.ContextActivity Is Nothing) Then
                Throw New ArgumentException("childContext", SR.GetString("Error_MissingContextActivityProperty"))
            End If
            If Not Me.executionContexts.Contains(childContext) Then
                Throw New ArgumentException
            End If
            If ((childContext.Activity.ContextActivity.ExecutionStatus <> ActivityExecutionStatus.Closed) AndAlso (childContext.Activity.ContextActivity.ExecutionStatus <> ActivityExecutionStatus.Initialized)) Then
                Throw New InvalidOperationException(SR.GetString(CultureInfo.CurrentCulture, "Error_CannotCompleteContext"))
            End If
            Dim item As ActivityExecutionContextInfo = [TryCast](childContext.Activity.ContextActivity.GetValue(Activity.ActivityExecutionContextInfoProperty),ActivityExecutionContextInfo)
            Dim list As IList([Of] Activity) = DirectCast(Me.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty), IList([Of] Activity))
            If ((list Is Nothing) OrElse Not list.Contains(childContext.Activity.ContextActivity)) Then
                Throw New ArgumentException
            End If
            Dim needsCompensation As Boolean = childContext.Activity.NeedsCompensation
            If (needsCompensation OrElse forcePersist) Then
                Dim list2 As List([Of] ActivityExecutionContextInfo) = [TryCast](Me.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty),List([Of] ActivityExecutionContextInfo))
                If (list2 Is Nothing) Then
                    list2 = New List([Of] ActivityExecutionContextInfo)
                    Me.ownerContext.Activity.ContextActivity.SetValue(Activity.CompletedExecutionContextsProperty, list2)
                End If
                If needsCompensation Then
                    item.Flags = PersistFlags.NeedsCompensation
                End If
                If forcePersist Then
                    item.Flags = DirectCast(CByte((item.Flags Or PersistFlags.ForcePersist)), PersistFlags)
                End If
                item.SetCompletedOrderId(Me.ownerContext.Activity.IncrementCompletedOrderId)
                list2.Add(item)
                Me.ownerContext.Activity.WorkflowCoreRuntime.SaveContextActivity(childContext.Activity)
            End If
            list.Remove(childContext.Activity.ContextActivity)
            Me.executionContexts.Remove(childContext)
            If (childContext.Activity.ContextActivity.CanUninitializeNow AndAlso (childContext.Activity.ContextActivity.ExecutionResult <> ActivityExecutionResult.Uninitialized)) Then
                childContext.Activity.ContextActivity.Uninitialize(Me.ownerContext.Activity.RootActivity.WorkflowCoreRuntime)
                childContext.Activity.ContextActivity.SetValue(Activity.ExecutionResultProperty, ActivityExecutionResult.Uninitialized)
            End If
            Me.ownerContext.Activity.WorkflowCoreRuntime.UnregisterContextActivity(childContext.Activity)
            If (Not needsCompensation AndAlso Not forcePersist) Then
                childContext.Activity.Dispose
            End If
        End Sub

        Public Function CreateExecutionContext(ByVal activity As Activity) As ActivityExecutionContext
            Dim context2 As ActivityExecutionContext
            If (Me.ownerContext Is Nothing) Then
                Throw New ObjectDisposedException("ActivityExecutionContextManager")
            End If
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            If Not Me.ownerContext.IsValidChild(activity, True) Then
                Throw New ArgumentException(SR.GetString("AEC_InvalidActivity"), "activity")
            End If
            Dim item As Activity = activity.Clone
            DirectCast(item, IDependencyObjectAccessor).InitializeInstanceForRuntime(Me.ownerContext.Activity.WorkflowCoreRuntime)
            Dim queue As New Queue([Of] Activity)
            queue.Enqueue(item)
            Do While (queue.Count <> 0)
                Dim activity3 As Activity = queue.Dequeue
                If (activity3.ExecutionStatus <> ActivityExecutionStatus.Initialized) Then
                    activity3.ResetAllKnownDependencyProperties
                    Dim activity4 As CompositeActivity = [TryCast](activity3,CompositeActivity)
                    If (Not activity4 Is Nothing) Then
                        Dim i As Integer
                        For i = 0 To activity4.EnabledActivities.Count - 1
                            queue.Enqueue(activity4.EnabledActivities.Item(i))
                        Next i
                        Dim flow As ISupportAlternateFlow = activity4
                        If (Not flow Is Nothing) Then
                            Dim j As Integer
                            For j = 0 To flow.AlternateFlowActivities.Count - 1
                                queue.Enqueue(flow.AlternateFlowActivities.Item(j))
                            Next j
                        End If
                    End If
                End If
            Loop
            Dim list As IList([Of] Activity) = DirectCast(Me.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty), IList([Of] Activity))
            If (list Is Nothing) Then
                list = New List([Of] Activity)
                Me.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, list)
            End If
            list.Add(item)
            Dim info As New ActivityExecutionContextInfo(activity.QualifiedName, Me.ownerContext.WorkflowCoreRuntime.GetNewContextActivityId, Guid.NewGuid, Me.ownerContext.ContextId)
            item.SetValue(Activity.ActivityExecutionContextInfoProperty, info)
            item.SetValue(Activity.ActivityContextGuidProperty, info.ContextGuid)
            Dim context As ActivityExecutionContext = Nothing
            Try 
                Me.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(item)
                context = New ActivityExecutionContext(item)
                Me.executionContexts.Add(context)
                context.InitializeActivity(context.Activity)
                context2 = context
            Catch exception1 As Exception
                If (Not context Is Nothing) Then
                    Me.CompleteExecutionContext(context)
                Else
                    list.Remove(item)
                End If
                Throw
            End Try
            Return context2
        End Function

        Friend Function DiscardPersistedExecutionContext(ByVal contextInfo As ActivityExecutionContextInfo) As ActivityExecutionContext
            If (contextInfo Is Nothing) Then
                Throw New ArgumentNullException("contextInfo")
            End If
            Dim list As IList([Of] ActivityExecutionContextInfo) = [TryCast](Me.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty),IList([Of] ActivityExecutionContextInfo))
            If ((list Is Nothing) OrElse Not list.Contains(contextInfo)) Then
                Throw New ArgumentException
            End If
            Dim item As Activity = Me.ownerContext.WorkflowCoreRuntime.LoadContextActivity(contextInfo, Me.ownerContext.Activity.ContextActivity.GetActivityByName(contextInfo.ActivityQualifiedName))
            DirectCast(item, IDependencyObjectAccessor).InitializeInstanceForRuntime(Me.ownerContext.Activity.WorkflowCoreRuntime)
            Dim list2 As IList([Of] Activity) = DirectCast(Me.ownerContext.Activity.ContextActivity.GetValue(Activity.ActiveExecutionContextsProperty), IList([Of] Activity))
            If (list2 Is Nothing) Then
                list2 = New List([Of] Activity)
                Me.ownerContext.Activity.ContextActivity.SetValue(Activity.ActiveExecutionContextsProperty, list2)
            End If
            list2.Add(item)
            Me.ownerContext.Activity.WorkflowCoreRuntime.RegisterContextActivity(item)
            Dim context As New ActivityExecutionContext(item)
            Me.executionContexts.Add(context)
            WorkflowTrace.Runtime.TraceEvent(TraceEventType.Information, 0, "Revoking context {0}:{1}", New Object() { context.ContextId, context.Activity.ContextActivity.QualifiedName })
            list.Remove(contextInfo)
            Return context
        End Function

        Friend Sub Dispose()
            If (Not Me.ownerContext Is Nothing) Then
                Dim context As ActivityExecutionContext
                For Each context In Me.ExecutionContexts
                    DirectCast(context, IDisposable).Dispose
                Next
                Me.ownerContext = Nothing
            End If
        End Sub

        Public Function GetExecutionContext(ByVal activity As Activity) As ActivityExecutionContext
            If (Me.ownerContext Is Nothing) Then
                Throw New ObjectDisposedException("ActivityExecutionContextManager")
            End If
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            Dim info As ActivityExecutionContextInfo = [TryCast](activity.GetValue(Activity.ActivityExecutionContextInfoProperty),ActivityExecutionContextInfo)
            Dim context As ActivityExecutionContext
            For Each context In Me.ExecutionContexts
                If (info Is Nothing) Then
                    If (context.Activity.ContextActivity.QualifiedName = activity.QualifiedName) Then
                        Return context
                    End If
                ElseIf context.ContextGuid.Equals(info.ContextGuid) Then
                    Return context
                End If
            Next
            Return Nothing
        End Function

        Public Function GetPersistedExecutionContext(ByVal contextGuid As Guid) As ActivityExecutionContext
            If (Me.ownerContext Is Nothing) Then
                Throw New ObjectDisposedException("ActivityExecutionContextManager")
            End If
            Dim list As IList([Of] ActivityExecutionContextInfo) = [TryCast](Me.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty),IList([Of] ActivityExecutionContextInfo))
            If (list Is Nothing) Then
                Throw New ArgumentException
            End If
            Dim contextInfo As ActivityExecutionContextInfo = Nothing
            Dim info2 As ActivityExecutionContextInfo
            For Each info2 In list
                If ((info2.ContextGuid = contextGuid) AndAlso (CByte((info2.Flags And PersistFlags.ForcePersist)) <> 0)) Then
                    contextInfo = info2
                    Exit For
                End If
            Next
            If (contextInfo Is Nothing) Then
                Throw New ArgumentException
            End If
            contextInfo.Flags = DirectCast(CByte((CInt(contextInfo.Flags) And &HFD)), PersistFlags)
            Return Me.DiscardPersistedExecutionContext(contextInfo)
        End Function


        ' Properties
        Friend ReadOnly Property CompletedExecutionContexts As ReadOnlyCollection([Of] ActivityExecutionContextInfo)
            Get
                Dim list As List([Of] ActivityExecutionContextInfo) = [TryCast](Me.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty),List([Of] ActivityExecutionContextInfo))
                list = If((list Is Nothing), New List([Of] ActivityExecutionContextInfo), list)
                Return list.AsReadOnly
            End Get
        End Property

        Public ReadOnly Property ExecutionContexts As ReadOnlyCollection([Of] ActivityExecutionContext)
            Get
                If (Me.ownerContext Is Nothing) Then
                    Throw New ObjectDisposedException("ActivityExecutionContextManager")
                End If
                Return New ReadOnlyCollection([Of] ActivityExecutionContext)(Me.executionContexts)
            End Get
        End Property

        Public ReadOnly Property PersistedExecutionContexts As IEnumerable([Of] Guid)
            Get
                If (Me.ownerContext Is Nothing) Then
                    Throw New ObjectDisposedException("ActivityExecutionContextManager")
                End If
                Dim list As List([Of] ActivityExecutionContextInfo) = [TryCast](Me.ownerContext.Activity.ContextActivity.GetValue(Activity.CompletedExecutionContextsProperty),List([Of] ActivityExecutionContextInfo))
                list = If((list Is Nothing), New List([Of] ActivityExecutionContextInfo), list)
                Dim list2 As New List([Of] Guid)
                Dim info As ActivityExecutionContextInfo
                For Each info In list
                    If (CByte((info.Flags And PersistFlags.ForcePersist)) <> 0) Then
                        list2.Add(info.ContextGuid)
                    End If
                Next
                Return list2
            End Get
        End Property


        ' Fields
        Private executionContexts As List([Of] ActivityExecutionContext) = New List([Of] ActivityExecutionContext)
        Private ownerContext As ActivityExecutionContext
    End Class
End Namespace

